# --*-- coding: utf-8 --*--

"""
日志系统，日志写入文件，控制台输出
"""

import logging
import sys
import os
import time
from datetime import datetime
from typing import Tuple, NoReturn, List
import colorlog
from logging.handlers import RotatingFileHandler

from src import Singleton
from src.config.logconfig import Config

if hasattr(sys, '_getframe'):
	# 0-当前frame, 1-self._get_caller_frame_info, 2-self._message_format, 3.self.debug/info/warning/error, 4. caller
	caller_frame = lambda: sys._getframe(4)
else:  # pragma: no cover
	def caller_frame():
		"""Return the caller's stack frame."""
		try:
			raise Exception
		except Exception:
			return sys.exc_info()[2].tb_frame.f_back.f_back.f_back.f_back


@Singleton
class Log(object):

	def __init__(self):
		self.logger = logging.getLogger('WebUIAutoTest')
		today = datetime.now().strftime("%Y%m%d")
		self.ch = self._init_console_handle()  # 控制台输出
		self.fh = self._init_file_handler(
			log_file_path=os.path.join(Config.project_dir, "Log", f"log_{today}.log"))  # 文件输出
		# 添加Handler
		self.logger.addHandler(self.ch)
		self.logger.addHandler(self.fh)
		self.logger.setLevel(Config.logging_level)

	def __exit__(self):
		self.__close_handler(self.fh)

	@staticmethod
	def _init_file_handler(log_file_path):
		"""
		创建日志记录器handler用于收集日志
		:return:
		"""
		file_handler = RotatingFileHandler(filename=log_file_path, encoding="utf-8")
		return file_handler

	@staticmethod
	def _init_console_handle():
		"""
		创建终端日志记录器handler，用于输出到控制台
		:return:
		"""
		console_handle = colorlog.StreamHandler()
		formatter = colorlog.ColoredFormatter(fmt="%(log_color)s%(message)s", log_colors=Config.log_colors_config)
		console_handle.setFormatter(formatter)
		return console_handle

	@staticmethod
	def _close_log_formatter(file_handler):
		"""
		关闭handler
		:param file_handler: 日志记录器
		:return:
		"""
		file_handler.close()

	def _get_caller_frame_info(self) -> Tuple[str, str, int]:
		"""
		:return: 代码文件路径, 函数名, 行号
		"""
		f = caller_frame()
		co = f.f_code
		return co.co_filename, co.co_name, f.f_lineno

	def _message_format(self, level: str, msg: str) -> str:
		time = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
		file, func, lineno = self._get_caller_frame_info()
		lineno = str(lineno)
		file = os.path.basename(file)
		file_func_lineno = file + "-" + func + "-" + lineno
		# 格式化输出
		msg = "{time:<29}{level:<10}{msg}{file_func_lineno}".format(time="[" + time + "]",
																	level="[" + level + "]",
																	file_func_lineno="[ in " + file_func_lineno + "]",
																	msg="[信息:" + msg + "]")
		return msg

	# def _log_format(self):
	# 	fmt_string = "%(message)s"
	# 	fmt = colorlog.ColoredFormatter(fmt_string)

	def debug(self, msg: str, *args, **kwargs) -> NoReturn:
		msg = self._message_format(level="DEBUG", msg=msg)
		self.logger.debug(msg, *args, **kwargs)

	def info(self, msg: str, *args, **kwargs) -> NoReturn:
		msg = self._message_format(level="INFO", msg=msg)
		self.logger.info(msg, *args, **kwargs)

	def warning(self, msg: str, *args, **kwargs) -> NoReturn:
		msg = self._message_format(level="WARNING", msg=msg)
		self.logger.warning(msg, *args, **kwargs)

	def error(self, msg: str, *args, **kwargs) -> NoReturn:
		msg = self._message_format(level="ERROR", msg=msg)
		self.logger.error(msg, *args, **kwargs)

	def critical(self, msg: str, *args, **kwargs) -> NoReturn:
		msg = self._message_format(level="CRITICAL", msg=msg)
		self.logger.critical(msg, *args, **kwargs)


def get_latest_log() -> str:
	"""
		获取当前实时最新的日志文件
	:return: 文件名
	"""
	log_dir = os.path.join(Config.project_dir, 'Log')
	max_mtime = 0
	max_mtime_file = ''
	for f in os.listdir(log_dir):
		if f.split('.')[-1] == 'log':
			mtime = os.path.getmtime(os.path.join(log_dir, f))
			if mtime > max_mtime:
				max_mtime = mtime
				max_mtime_file = f
	return max_mtime_file


def get_all_logs() -> List:
	"""
		 获取当前Log目录下所有日志文件，按照文件名日期降序排序
	"""
	log_dir = os.path.join(Config.project_dir, 'Log')
	logs = filter(lambda x: x.split('.')[-1] == 'log', os.listdir(log_dir))
	return sorted(logs, reverse=True)


def remove_logs() -> NoReturn:
	"""
	删除过期日志，默认一个月
	:return:
	"""
	now_time_stamp = time.time()
	logs_list = sorted(get_all_logs())
	Log_path = os.path.join(Config.project_dir, "Log")
	for log in logs_list:
		log1 = os.path.splitext(log)[0]
		time_stamp = time.mktime(time.strptime(log1.split("_")[1], "%Y%m%d"))
		# 删除30天前的日志文件
		if now_time_stamp - time_stamp >= 2592000:
			os.remove(os.path.join(Log_path, log))


logger = Log()

if __name__ == '__main__':
	logger.critical("-------------------------")
	logger.error("-------------------------")
	logger.warning("-------------------------")
	logger.info("-------------------------")
	logger.debug("-------------------------")
	remove_logs()
